package com.hzw.saas.web.sso.security;

import com.hzw.saas.common.security.token.MyDefaultAccessTokenConverter;
import com.hzw.saas.common.security.token.SaasTokenService;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.ClassPathResource;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.token.AccessTokenConverter;
import org.springframework.security.oauth2.provider.token.DefaultAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
import org.springframework.security.oauth2.provider.token.store.KeyStoreKeyFactory;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider;

import java.util.Arrays;
import java.util.Collections;

/**
 * @author zzl
 * @since 12/21/2020
 */
@Configuration
@RequiredArgsConstructor
public class SsoSecurityTokenConfig {
    private static final String JKS_PATH = "saasr2.jks";
    private static final String KEY_PASS = "hzwsaasr2";
    private static final String KEY_STORE_ALIAS = "saasr2";

    private final UserDetailsService userDetailsService;
    private final ClientDetailsService clientDetailsService;

    @Bean
    public TokenStore tokenStore() {
        return new JwtTokenStore(jwtAccessTokenConverter());
    }

    @Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        KeyStoreKeyFactory factory = new KeyStoreKeyFactory(new ClassPathResource(JKS_PATH), KEY_PASS.toCharArray());
        converter.setKeyPair(factory.getKeyPair(KEY_STORE_ALIAS));
        converter.setAccessTokenConverter(accessTokenConverter());
        return converter;
    }

    // 解决SecurityUtils.getUser()错误的问题
    private AccessTokenConverter accessTokenConverter() {
        DefaultAccessTokenConverter accessTokenConverter = new DefaultAccessTokenConverter();
        MyDefaultAccessTokenConverter userAuthenticationConverter = new MyDefaultAccessTokenConverter();
        accessTokenConverter.setUserTokenConverter(userAuthenticationConverter);
        return accessTokenConverter;
    }

    @Bean
    @Primary
    public SaasTokenService tokenServices() {
        SaasTokenService tokenServices = new SaasTokenService();
        tokenServices.setTokenStore(tokenStore());
        tokenServices.setClientDetailsService(clientDetailsService);
        tokenServices.setSupportRefreshToken(true);
        tokenServices.setReuseRefreshToken(true);
        TokenEnhancerChain chain = new TokenEnhancerChain();
        chain.setTokenEnhancers(Arrays.asList(jwtAccessTokenConverter(), new CustomAdditionalInformation()));
        tokenServices.setTokenEnhancer(chain);
        addUserDetailsService(tokenServices);
        return tokenServices;
    }

    private void addUserDetailsService(SaasTokenService tokenServices) {
        PreAuthenticatedAuthenticationProvider provider = new PreAuthenticatedAuthenticationProvider();
        provider.setPreAuthenticatedUserDetailsService(new UserDetailsByNameServiceWrapper<>(userDetailsService));
        tokenServices.setAuthenticationManager(new ProviderManager(Collections.singletonList(provider)));
    }

}
